package com.glsc.ngateway.oaflow.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.common.enums.ExceptionConstant;
import com.glsc.ngateway.common.api.common.enums.GatewayConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TFlowAppendixHistoryTable;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowAppendTable;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowRelativeMetaTable;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TFlowAppendixHistoryTableRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowAppendTableRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowRelativeMetaTableRepository;
import com.glsc.ngateway.oaflow.exception.BusinessException;
import com.glsc.ngateway.oaflow.utils.DateUtils;
import com.glsc.ngateway.oaflow.utils.DocUtils;
import com.glsc.ngateway.oaflow.utils.ZipUtils;
import com.glsc.ngateway.oaflow.wsclients.wsdl.download.DownloadOAdocs;
import com.glsc.ngateway.oaflow.wsclients.wsdl.download.DownloadOAdocsResponse;
import com.glsc.ngateway.oaflow.wsclients.wsdl.download.WsClientDownload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.ws.client.WebServiceClientException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;

@Component
public class AppendixService {

    Logger logger = LoggerFactory.getLogger(AppendixService.class);

    @Autowired
    TOaFlowAppendTableRepository appendRepo;
    @Autowired
    OracleJdbcTemplate oracleJdbcTemplate;

    @Autowired
    TOaFlowRelativeMetaTableRepository relativeMetaTableRepository;

    @Autowired
    TFlowAppendixHistoryTableRepository flowAppendixHistoryTableRepository;

    @Autowired
    private GatewayConstant gatewayConstant;

    @Autowired
    WsClientDownload wsClientDownload;

    @Value("${app.docWebUrl}")
    public String DOC_WEB_URL;

    @Autowired
    private FlowService flowService;

    //对应controller uploadDoc方法

    public String updateAppendix(String fileName, String filePath, MultipartFile file) throws IOException {
        return updateAppendix(fileName, filePath, file.getBytes());
    }
    public String updateAppendix(String fileName, String filePath, byte[] file) throws IOException {
        String appendixId = UUID.randomUUID().toString();
        //通过flowable上传附件用20220101格式
        //通过oaflow上传附件用2022-01-01格式  要注意 现在也统一改成20220101格式
        String today = DateUtils.today();
        String resPath = DocUtils.saveFile(file, filePath + today + "/" + appendixId + "/", fileName);
        if (null == fileName || fileName.equals("")) {
            throw new BusinessException(ExceptionConstant.BussinessException, "上传文件异常，文件名称为空");
        }
        if (resPath.equals(GatewayConstant.EXCEPTION)) {
            throw new BusinessException(ExceptionConstant.IO, "上传文件异常，文件名称为：" + fileName);
        }
        appendRepo.save(new TOaFlowAppendTable(fileName, resPath, appendixId));
        return DOC_WEB_URL + appendixId;
    }

    //对应controller oaDownloadAppendix方法
    public String getAppendixPathById(String appendixID) {
        return appendRepo.getAppendixPathById(appendixID);
    }

    public ResponseEntity<byte[]> downSingleAppendixFromOA(String url, String fileName, HttpServletRequest request) throws IOException {

        // 统一资源
        URL url1 = new URL(url);
        // 连接类的父类，抽象类
        URLConnection urlConnection = url1.openConnection();
        // http的连接类
        HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
        //设置超时
        httpURLConnection.setConnectTimeout(1000 * 5);
        //设置请求方式，默认是GET
        httpURLConnection.setRequestMethod("GET");
        // 设置字符编码
        httpURLConnection.setRequestProperty("Charset", "UTF-8");
        // 打开到此 URL引用的资源的通信链接（如果尚未建立这样的连接）。
        httpURLConnection.connect();
        // 文件大小
        int fileLength = httpURLConnection.getContentLength();
        // 控制台打印文件大小
        System.out.println("您要下载的文件大小为:" + fileLength / (1024) + "KB");

        // 建立链接从请求中获取数据
        URLConnection con = url1.openConnection();
        BufferedInputStream bin = new BufferedInputStream(httpURLConnection.getInputStream());

        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> entity = null;
        InputStream in = null;
        byte[] bytes = new byte[0];
        //in = new FileInputStream(new File(url));
        // bytes = new byte[in.available()];
        bytes = new byte[fileLength];
        String imageName = fileName;
        //处理IE下载文件的中文名称乱码的问题
        String header = request.getHeader("User-Agent").toUpperCase();
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            imageName = URLEncoder.encode(imageName, "utf-8");
            imageName = imageName.replace("+", "%20"); //IE下载文件名空格变+号问题
        } else {
            imageName = new String(imageName.getBytes(), "iso-8859-1");
        }
        while (true) {
            int read = bin.read(bytes);
            //判断是不是读到了数据流的末尾 ，防止出现死循环。
            if (read == -1) {
                break;
            }
        }
        headers.add("Content-Disposition", "attachment;filename=" + imageName);
        return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);


    }

//***************************************以下部分待测试******************************************

    //对应controller  downloadAppendix方法
    public List<String[]> getAllFlowDocIds(String requestId, String flowId) {

        List<String[]> docList = new ArrayList<>();
        List<String> sqlList = getAppendixSqlList(requestId, flowId);
        List<Map> messageList = getDataBySql(sqlList);
        if (!messageList.isEmpty()) {
            for (Map map : messageList) {
                String appendIds = map.get("APPENDID").toString();
                List<String[]> downList = getDownloadUrl(appendIds);
                if (!downList.isEmpty()) {
                    docList.addAll(downList);
                }
            }
        }
        return docList;
    }

    public List<String[]> getDownloadUrl(String appendIds) {
        List<String[]> downList = new ArrayList<String[]>();
        if (!"".equals(appendIds)) {
            String[] appendArr = appendIds.split(",");
            for (String docId : appendArr) {
                String listUrl[] = callAppendixService(docId);
                if (listUrl != null) {
                    downList.add(listUrl);
                }
            }
        }
        return downList;
    }

    public String[] callAppendixService(String docId) {
//        DownDocService downDocService = new DownDocService();
//        DownDocServicePortType downDocServicePortType = downDocService.getDownDocServiceHttpPort();
//        String result = downDocServicePortType.downloadOAdocs(docId);

        DownloadOAdocs req = new DownloadOAdocs();
        req.setIn0(docId);
//        DownloadOAdocsResponse res = (DownloadOAdocsResponse) wsClientDownload.callWebService(req);
        DownloadOAdocsResponse res = new DownloadOAdocsResponse();
        try {
            // 尝试使用主配置发送请求
            res =  (DownloadOAdocsResponse) wsClientDownload.callWebService(req);
        } catch (WebServiceClientException e) {
            // 捕获WebServiceClientException异常，这通常表示网络问题或Web服务不可用
            // 在这里可以记录日志或执行其他错误处理逻辑
            // 然后尝试使用备用配置发送请求
            logger.error("oaCallEndException"+e);
            res = (DownloadOAdocsResponse) wsClientDownload.callWebServiceBack(req);
        }
        String result = res.getOut();

        JSONObject jsonObject = JSON.parseObject(result);
        if (jsonObject.containsKey("code")) {
            if (jsonObject.get("code").toString().equals("success")) {
                Object url = jsonObject.get("url");
                String filename = jsonObject.getString("filename");
                if (null != url && !url.toString().equals("") && StrUtil.isNotEmpty(filename)) {
                    return new String[]{jsonObject.get("url").toString(), filename};
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    public List<String> getAppendixSqlList(String requestId, String workFlowId) {

        List<String> sqlList = new ArrayList<String>();
        List<TOaFlowRelativeMetaTable> ftrList = relativeMetaTableRepository.findByWorkFlowId(workFlowId);
        for (TOaFlowRelativeMetaTable ftr : ftrList) {
            if (ftr.getWorkFlowTable().equals(ftr.getWorkFlowDetailTable())) {
                String sql = "select " + ftr.getFieldAppend() + " appendId from " + ftr.getWorkFlowTable() + " where REQUESTID = " + requestId + " and " + ftr.getFieldAppend() + " is not null";
                sqlList.add(sql);
            } else {
                String sql = "select " + ftr.getFieldAppend() + " appendId from " + ftr.getWorkFlowTable() + " a left join " + ftr.getWorkFlowDetailTable() + " b on a.id = b.MAINID where REQUESTID = " + requestId + " and " + ftr.getFieldAppend() + " is not null";
                sqlList.add(sql);
            }
        }
        return sqlList;
    }

    public List<Map> getDataBySql(String sql) {

        List<Map> dataList = new ArrayList<>();
        List rows = oracleJdbcTemplate.query(sql);
        for (int i = 0; i < rows.size(); i++) {
            Map dataMap = (Map) rows.get(i);
            dataList.add(dataMap);
        }
        return dataList;

    }

    public List<Map> getDataBySql(List<String> sqlList) {
        List<Map> dataList = new ArrayList<>();
        for (String sql : sqlList) {
            List rows = oracleJdbcTemplate.query(sql);
            for (int i = 0; i < rows.size(); i++) {
                Map<String, Object> dataMap = (Map<String, Object>) rows.get(i);
                for (String key : dataMap.keySet()) {
                    if (null != dataMap.get(key)) {
                        dataList.add(dataMap);
                    }
                }
            }
        }
        return dataList;
    }


    //对应controller downloadAppendix downloadDerivativeAppendix方法
    public ResponseEntity<byte[]> downAllAppendix(List<String[]> listUrl, String targetName, HttpServletRequest request) throws IOException {

        handleAppendixFromOaUrls(listUrl, targetName);
        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> entity = null;
        InputStream in = null;
        byte[] bytes = new byte[0];
        in = new FileInputStream(new File(targetName));
        bytes = new byte[in.available()];
        String imageName = targetName;
        //处理IE下载文件的中文名称乱码的问题
        String header = request.getHeader("User-Agent").toUpperCase();
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            imageName = URLEncoder.encode(imageName, "utf-8");
            imageName = imageName.replace("+", "%20"); //IE下载文件名空格变+号问题
        } else {
            imageName = new String(imageName.getBytes(), "iso-8859-1");
        }
        in.read(bytes);
        headers.add("Content-Disposition", "attachment;filename=" + imageName);
        return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
    }

    public void handleAppendixFromOaUrls(List<String[]> urlList, String targetDir) {
        List<File> fileList = new ArrayList<>();
        Map<String, Integer> fnMap = new HashMap<>();
        String batchId = UUID.randomUUID().toString();
        for (String[] url : urlList) {
            if (StrUtil.isNotBlank(url[0])) {
                String fileName = url[1];
                if (fnMap.containsKey(url[1])) {
                    fileName = url[1] + "(" + fnMap.get(url[1]) + ")";
                    fnMap.put(url[1], fnMap.get(url[1]) + 1);
                } else {
                    fnMap.put(url[1], 1);
                }
                File filePath = DocUtils.downLoadFromUrl(url[0], fileName, batchId, GatewayConstant.DOWNLOAD_FILE);
                fileList.add(filePath);
            }
        }
        if (fileList.size() > 0) {
            ZipUtils.toZips(fileList, targetDir);
        }
    }


    /**
     * 股衍增量查询流程附件接口
     *
     * @param appendixTypeList 流程表单附件类别
     */
    public Map<String, Object> isExistAppendix(@NotNull String requestId, @NotNull List<String> appendixTypeList
            , @NotNull String callSystemId, String isForce) {

        int workFlowId = flowService.getWorkflowIdByRequestId(requestId);
        if (workFlowId < 1) {
            throw new RuntimeException("未找到流程实例对应的流程类型信息");
        }

        /**查询表单附件列表*/
        List<String> docList = new ArrayList<>();
        for (String appendixType : appendixTypeList) {
            List<String> tmpDocList = getAppendixIds(requestId, String.valueOf(workFlowId), appendixType);
            if (CollectionUtil.isNotEmpty(tmpDocList)) {
                docList.addAll(tmpDocList);
            }
        }


        Map map = new HashMap<String, Object>();
        if (CollectionUtil.isEmpty(docList)) {
            map.put("isExist", "0");
        } else {
            //附件字段整体是否下载过的判断，如果表单字段有多个附件，有一个没下载过就认为是整体没下载过
            map.put("isExist", "2");// 表示系统已经下载过附件，然后不允许重复下载。
            for (String appendixType : appendixTypeList) {
                if (!countAppendixIdRepeat(requestId, callSystemId, isForce, appendixType, docList)) {//存在未下载的
                    map.put("isExist", "1");
                    break;
                }
            }
        }
        return map;
    }

    /**
     *
     * 根据流程表单指定附件字段查询附件id
     * * * * */
    public List<String> getAppendixIds(String requestId, String flowId, String appendixType) {

        List<String> docList = new ArrayList<>();
        List<String> sqlList = getDerivativeSqlList(requestId, flowId, appendixType);  //返回查询Sql

        if (CollectionUtil.isNotEmpty(sqlList)) {
            List<Map> messageList = getDataBySql(sqlList);
            if (null != messageList && !messageList.isEmpty()) {
                for (Map map : messageList) {
                    String appendIds = map.get("APPENDID").toString();
                    if (!"".equals(appendIds)) {
                        String[] appendArr = appendIds.split(",");
                        for (String docId : appendArr) {
                            docList.add(docId);
                        }
                    }
                }
            }
        }
        return docList;
    }

    /**
     * @param fieldAppend OA表单附件字段名称
     */
    public List<String> getDerivativeSqlList(String requestId, String workFlowId, String fieldAppend) {

        List<String> sqlList = new ArrayList<>();

        //查询流程表单附件的配置
        List<TOaFlowRelativeMetaTable> ftrList = relativeMetaTableRepository.findByWorkFlowIdAndFieldAppend(workFlowId, fieldAppend);

        if (CollectionUtil.isNotEmpty(ftrList)) {
            for (TOaFlowRelativeMetaTable ftr : ftrList) {
                if (ftr.getWorkFlowTable().equals(ftr.getWorkFlowDetailTable())) {//关联主表
                    String sql = "select " + ftr.getFieldAppend() + " appendId from " + ftr.getWorkFlowTable() + " where REQUESTID = " + requestId;
                    sqlList.add(sql);
                } else {//关联明细表
                    String sql = "select " + ftr.getFieldAppend() + " appendId from " + ftr.getWorkFlowTable() + " a left join " + ftr.getWorkFlowDetailTable() + " b on a.id = b.MAINID where REQUESTID = " + requestId;
                    sqlList.add(sql);
                }
            }
        }
        return sqlList;
    }

    /**
     * 检查oa流程文件，整体是否被系统记录过
     *
     * @return 是否本地有下载记录
     * * *
     */
    public boolean countAppendixIdRepeat(String requestId, String callSystemId, String isForce, String appendixFields, List<String> docList) {
        boolean existAppendRecord = true;//本地有下载记录

        if (isForce.equals(GatewayConstant.FLAG_ZERO)) { // 非强制下载附件&本地有下载记录，则返回true
            for (String docId : docList) {
                Integer countNum = flowAppendixHistoryTableRepository.countAppendIdRepeat(docId, requestId, callSystemId);
                if (countNum <= 0) {
                    TFlowAppendixHistoryTable re = flowAppendixHistoryTableRepository.save(new TFlowAppendixHistoryTable(requestId, docId, callSystemId, GatewayConstant.SYSTEM_INFO_MAP.get(callSystemId), appendixFields));
                    existAppendRecord = false;//有一个文件没下载记录就标记
                }
            }
        } else {
            existAppendRecord = false;//强制下载，视同没有下载记录
        }
        return existAppendRecord;
    }

    public String getAppendixSql(String requestId, String workFlowId) {
        List<TOaFlowRelativeMetaTable> ftr = relativeMetaTableRepository.findByWorkFlowId(workFlowId);
        if (ftr != null && ftr.size() > 0) {
            String sql = "select " + ftr.get(0).getFieldAppend() + " appendId from " + ftr.get(0).getWorkFlowTable() + " a left join "
                    + ftr.get(0).getWorkFlowDetailTable() + " b on a.id = b.MAINID where REQUESTID = " + requestId;
            return sql;
        }
        return null;
    }



    //对应controller downloadDerivativeAppendix方法
    /**
     * 根据表单附件字段获取下载地址
     * * * */
    public List<String[]> getDerivativeFlowDocIds(String requestId, String flowId, String appendixType) {
        List<String[]> docList = new ArrayList<>();
        List<String> idList = getAppendixIds(requestId, flowId, appendixType);

        if (CollectionUtil.isEmpty(idList)) {
//            throw new BusinessException(ExceptionConstant.EmptyException, "数据为空，FlowId 为：" + flowId + ",requestId为:" + requestId);
        } else {
            for (String docId : idList) {
                docList.addAll(getDownloadUrl(docId));
            }
        }
        return docList;
    }


    public ResponseEntity<byte[]> downSingleAppendixFromOANew(String urlStr, String fileName, HttpServletRequest request) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置超时间为3秒
        conn.setConnectTimeout(5 * 1000);
        //防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> entity = null;

        //得到输入流
        InputStream inputStream = conn.getInputStream();
        //获取自己数组
        byte[] getData = readInputStream(inputStream);
//        //文件保存位置
//        File saveDir = new File(savePath);
//        if(!saveDir.exists()){
//            saveDir.mkdir();
//        }
//        File file = new File(saveDir+File.separator+fileName);
//        FileOutputStream fos = new FileOutputStream(file);
//        fos.write(getData);
//        if(fos!=null){
//            fos.close();
//        }
//        if(inputStream!=null){
//            inputStream.close();
//        }
        System.out.println("info:" + url + " download success");

        String header = request.getHeader("User-Agent").toUpperCase();
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            fileName = URLEncoder.encode(fileName, "utf-8");
            fileName = fileName.replace("+", "%20"); //IE下载文件名空格变+号问题
        } else {
            fileName = new String(fileName.getBytes(), "iso-8859-1");
        }
        headers.add("Content-Disposition", "attachment;filename=" + fileName);
        return new ResponseEntity<byte[]>(getData, headers, HttpStatus.OK);
    }


    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }
}
